package com.baoteng.rbspy.config;

import java.net.InetSocketAddress;
import java.net.Proxy;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.X509Certificate;
import java.util.concurrent.TimeUnit;

import javax.annotation.PostConstruct;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.baoteng.rbspy.interceptor.HttpLoginInterceptor;
import com.baoteng.rbspy.interceptor.cookie.OKHttpCookieJar;

import okhttp3.ConnectionPool;
import okhttp3.OkHttpClient;
import okhttp3.logging.HttpLoggingInterceptor;

@Configuration
public class HttpClientConfig {

	@Value("${httpClient.pooling.maxIdleConnections}")
	private Integer maxIdleConnections;

	@Value("${httpClient.pooling.keepAliveDurationNs}")
	private Integer keepAliveDurationNs;

	@Value("${httpClient.connectTimeout}")
	private Integer connectTimeout;

	@Value("${httpClient.readTimeout}")
	private Integer readTimeout;

	@Value("${httpClient.writeTimeout}")
	private Integer writeTimeout;

	@Value("${httpClient.logging:false}")
	private boolean isLogging;

	@Value("${httpClient.proxy:false}")
	private boolean isProxy;

	@Value("${httpClient.proxy.host:}")
	private String proxyHost;

	@Value("${httpClient.proxy.port:80}")
	private Integer proxyPort;

	@Value("${httpClient.proxy.user:}")
	private String proxyUser;

	@Value("${httpClient.proxy.pwd:}")
	private String proxyPwd;

	private HttpLoggingInterceptor okHttploggingInterceptor;

	private X509TrustManager ALL_TRUST_MANAGER = new X509TrustManager() {
		public java.security.cert.X509Certificate[] getAcceptedIssuers() {
			X509Certificate[] x509Certificates = new X509Certificate[0];
			return x509Certificates;
		}

		public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType) {
		}

		public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType) {
		}
	};
	private HostnameVerifier DO_NOT_VERIFY = new HostnameVerifier() {
		@Override
		public boolean verify(String hostname, SSLSession session) {
			return true;
		}
	};

	@PostConstruct
	public void init() {
		okHttploggingInterceptor = new HttpLoggingInterceptor();
		okHttploggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
	}

	@Bean(name = "okHttpClient")
	public OkHttpClient okHttpClient() {
		OkHttpClient.Builder builder = new OkHttpClient.Builder();
		ConnectionPool pool = new ConnectionPool(maxIdleConnections, keepAliveDurationNs, TimeUnit.SECONDS);
		Proxy proxy = Proxy.NO_PROXY;
		if (isProxy) {
			proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyHost, proxyPort));
		}
		if (isLogging) {
			builder.addNetworkInterceptor(okHttploggingInterceptor);
		}
		OKHttpCookieJar.Builder cookieJarBuilder = new OKHttpCookieJar.Builder();
		builder.connectionPool(pool).followRedirects(false).followSslRedirects(false)
				.proxy(proxy).connectTimeout(connectTimeout, TimeUnit.SECONDS)
				.cookieJar(cookieJarBuilder.build()).readTimeout(readTimeout, TimeUnit.SECONDS)
				.writeTimeout(writeTimeout, TimeUnit.SECONDS).retryOnConnectionFailure(true);
		return builder.build();
	}

	@Bean(name = "okHttpsClient")
	public OkHttpClient okHttpsClient() {
		OkHttpClient.Builder builder = new OkHttpClient.Builder();
		ConnectionPool pool = new ConnectionPool(maxIdleConnections, keepAliveDurationNs, TimeUnit.SECONDS);
		Proxy proxy = Proxy.NO_PROXY;
		if (isProxy) {
			proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyHost, proxyPort));
		}
		if (isLogging) {
			builder.addNetworkInterceptor(okHttploggingInterceptor);
		}
		OKHttpCookieJar.Builder cookieJarBuilder = new OKHttpCookieJar.Builder();
		builder.proxy(proxy).followRedirects(true).followSslRedirects(true)
				.connectionPool(pool).connectTimeout(connectTimeout, TimeUnit.SECONDS).addInterceptor(new HttpLoginInterceptor())
				.readTimeout(readTimeout, TimeUnit.SECONDS).writeTimeout(writeTimeout, TimeUnit.SECONDS)
				.cookieJar(cookieJarBuilder.build()).retryOnConnectionFailure(true)
				.sslSocketFactory(createIgnoreVerifySSL(), ALL_TRUST_MANAGER).hostnameVerifier(DO_NOT_VERIFY);
		return builder.build();
	}

	/**
	 * 用于单向ssl绕过验证
	 * 
	 * @return
	 * @throws NoSuchAlgorithmException
	 * @throws KeyManagementException
	 */
	private SSLSocketFactory createIgnoreVerifySSL() {
		try {
			SSLContext sc = SSLContext.getInstance("TLSv1");
			TrustManager[] trustAllCerts = new TrustManager[] { ALL_TRUST_MANAGER };
			sc.init(null, trustAllCerts, new java.security.SecureRandom());
			// sc = SSLContexts.custom()
			// .loadTrustMaterial(new File("d:/jks/cicc_server_test.jks"),
			// "123456".toCharArray(),
			// new TrustSelfSignedStrategy())
			// .loadKeyMaterial(new File("d:/jks/cicc_test.jks"), "123456".toCharArray(),
			// "123456".toCharArray())
			// .build();
			return sc.getSocketFactory();
		} catch (KeyManagementException | NoSuchAlgorithmException e) {
			e.printStackTrace();
			return null;
		}
	}
}
